/**
 * Classe de gestion d'une partie
 * @author Lo�c Mounier, Thomas Picard, Marianne Grandemenge
 */

package modele;

import java.io.IOException;
import java.io.Serializable;
import java.net.MulticastSocket;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;

import codebase.ICreerPartieReseau;
import codebase.IJeuInterface;
import codebase.IJoueur;
import codebase.IPartie;

public class Partie extends UnicastRemoteObject implements IPartie, Serializable {

	private static final long serialVersionUID = 1L;

	private ArrayList<Tour> listeTour;
	private Configuration configuration;
	private ArrayList<IJoueur> listeJoueur;
	// pour la notification des joeuurs
	private ArrayList<ICreerPartieReseau> listCreerPartieReseau;
	private ArrayList<IJeuInterface> listJeuInterface;
	public static MulticastSocket castSocket;

	public Partie() throws RemoteException {
		this.listeTour = new ArrayList<Tour>();
		Tour tourDebut = new Tour(1901, "Printemps");
		listeTour.add(tourDebut);
		configuration = new Configuration();
		listeJoueur = new ArrayList<IJoueur>();
		listCreerPartieReseau = new ArrayList<ICreerPartieReseau>();
		listJeuInterface = new ArrayList<IJeuInterface>();
		try {
			// TODO voir pour ajouter le bon port
			castSocket = new MulticastSocket(5000);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void addJoueurChat(Joueur j) {
		try {
			castSocket.joinGroup(j.getAdr());
		} catch (IOException e) {
			System.out.println("Erreur lors de l'entree au chat");
			e.printStackTrace();
		}
	}

	public void setConfiguation(Configuration config) {
		System.out.println("---Redefinition de la configuration---");
		configuration = config;
	}

	public Configuration getConfiguration() {
		return configuration;
	}

	public void play() {
		// Configuration partie
		// Definir la nb de joueur
		// Definir la durée des phases
		// Définir la dure total de la partie
		// Définir le nombre d'arsenaux à controler pour gagner
		// Tant que !fin de partie
		// Négociation
		// Redaction des ordres
		// Arbitrage
		// Dispersion/Retraite
		// Ajustement d'automne
	}

	public void ajouterJoueur(IJoueur j) throws RemoteException {
		listeJoueur.add(j);
		envoyerMessage(j.getNom() + " vient de se connecter.\n");
		System.out.println("");
		System.out.println("[serveur]Nouveau joueur : " + j.getNom() + "[/serveur]");
	}

	public void supprimerJoueur(IJoueur joueur) throws RemoteException {
		System.out.println(listeJoueur);
		IJoueur jToDelete = null;
		for (IJoueur j : listeJoueur) {
			if (j.getNom().equals(joueur.getNom())) {
				jToDelete = j;
			}
		}
		listeJoueur.remove(jToDelete);
		System.out.println(listeJoueur);
	}

	public Configuration getConfig() throws RemoteException {
		return configuration;
	}

	@Override
	public Carte getCarte() {
		return carte;
	}

	@Override
	public int getNbJoueurs() throws RemoteException {
		return listeJoueur.size();
	}

	@Override
	public void setNomJoueur(IJoueur j, String nom) throws RemoteException {
		for (IJoueur joueur : listeJoueur) {
			if (j.getId() == joueur.getId()) {
				joueur.setNom(nom);
			}
		}
		notifyJoueur(0);
	}

	@Override
	public HashMap<String, String> gerePuissanceJoueur(int idAction, IJoueur j, Puissance p)
			throws RemoteException {
		switch (idAction) {
		case 0:
			// Ajoute une puissance au joueur
			IJoueur jToAddPuissance = null;
			boolean present = false;
			for (IJoueur joueur : listeJoueur) {
				if (j.getId() == joueur.getId()) {
					jToAddPuissance = joueur;
				}
				for (Puissance pui : joueur.getListPuissance()) {
					if (p.getNom().equals(pui.getNom())) {
						present = true;
					}
				}
			}
			if (jToAddPuissance != null && !present) {
				jToAddPuissance.addPuissance(p);
			} else {
				System.err.println("Desole " + p.getNom() + " deja prit");
			}
			notifyJoueur(0);
			break;
		case 1:
			// Pour un joueur donne efface les puissances pres selectionnes
			for (IJoueur joueur : listeJoueur) {
				if (j.getId() == joueur.getId()) {
					joueur.clearPuissance();
				}
			}
			break;
		case 2:
			// Retourne une hashmap avec abreviationPuissance -> nomJoueur
			HashMap<String, String> hmPuiJoueur = new HashMap<String, String>();
			for (IJoueur joueur : listeJoueur) {
				for (Puissance pui : joueur.getListPuissance()) {
					hmPuiJoueur.put(pui.getAbreviation(), joueur.getNom());
				}
			}
			return hmPuiJoueur;
		}
		return null;
	}

	public Joueur getJoueurWithPuissance(Puissance p) throws RemoteException {
		Joueur res = null;
		for (IJoueur joueur : listeJoueur) {
			if (joueur.getListPuissance().contains(p)) {
				res = (Joueur) joueur;
			}
		}
		return res;

	}

	@Override
	public void gerePuissanceJoueur2(IJoueur j, ArrayList<Puissance> lp) throws RemoteException {
		// Ajoute une liste de puissance au joueur
		IJoueur jToAddPuissance = null;
		boolean present = false;
		for (IJoueur joueur : listeJoueur) {
			if (j.getId() == joueur.getId()) {
				jToAddPuissance = joueur;
			}
		}
		if (jToAddPuissance != null) {
			for (Puissance p : lp) {
				present = false;
				jToAddPuissance.addPuissance(p);
			}
		}
		notifyJoueur(0);
	}

	public void setConfigAttribute(int idAttribut, int valeur) throws RemoteException {
		System.out.println("");
		System.out.println("[serveur]Modification de l'att " + idAttribut + " avec la valeur "
				+ valeur + "[/serveur]");
		switch (idAttribut) {
		case 0:
			configuration.setNbJoueurs(valeur);
			notifyJoueur(0);
			break;
		case 1:
			configuration.setNbCentresRavitallementVictoire(valeur);
			notifyJoueur(1);
			break;
		case 2:
			configuration.setDureePartieTps(valeur);
			notifyJoueur(1);
			break;
		case 3:
			configuration.setDureePartieNbAnnees(valeur);
			notifyJoueur(1);
			break;
		case 4:
			configuration.setDureeNegociations(valeur);
			notifyJoueur(1);
			break;
		case 5:
			configuration.setDureeOrdres(valeur);
			notifyJoueur(1);
			break;
		case 6:
			configuration.setDureeDispersions(valeur);
			notifyJoueur(1);
			break;
		default:
			System.err.println("Erreur setConfigAttribute, tentative de set avec un mauvais id");
		}
	}

	public IJoueur getJoueurByName(String name) throws RemoteException {
		for (IJoueur joueur : listeJoueur) {
			if (joueur.getNom().equals(name)) {
				return joueur;
			}
		}
		return null;
	}

	public void sendMessage(String msg, String tabName, ArrayList<String> listeJoueursChat)
			throws RemoteException {
		for (String j : listeJoueursChat) {
			getJoueurByName(j).receiveMessage(msg, tabName, listeJoueursChat);
		}

	}

	public void notifyJoueur(int id) {
		// id = 0 -> Puissance, id = 1 -> Parametre
		System.out.println("[serveur]Notification des " + listCreerPartieReseau.size()
				+ " joueurs[/serveur]");
		int i = 1;
		for (ICreerPartieReseau p : listCreerPartieReseau) {
			i++;
			try {
				p.majData(id);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void connect(ICreerPartieReseau confPartie) throws RemoteException {
		this.listCreerPartieReseau.add(confPartie);
	}

	@Override
	public Tour getDernierTour() throws RemoteException {
		return listeTour.get(listeTour.size() - 1);
	}

	@Override
	public ArrayList<IJoueur> getListeJoueur() throws RemoteException {
		return listeJoueur;
	}

	@Override
	public void envoyerMessage(String s) throws RemoteException {
		for (ICreerPartieReseau p : listCreerPartieReseau) {
			p.receptionMessage(s);
		}
	}

	@Override
	public void passerAuJeu() throws RemoteException {
		System.out.println("[serveur]Lancement de toute les interface jeu[/serveur]");
		for (ICreerPartieReseau p : listCreerPartieReseau) {
			p.playPartie();
		}
	}

	@Override
	public void arbitrer() throws RemoteException {
		listeTour.get(listeTour.size() - 1).arbitrage(carte);
	}

	@Override
	public void addOrdre(String s) throws RemoteException {
		listeTour.get(listeTour.size() - 1).addOrdre(s);
	}

	public void removeOrdre(String s) throws RemoteException {
		listeTour.get(listeTour.size() - 1).removeOrdre(s);
	}

	@Override
	public void phaseSuivante() throws RemoteException {
		Tour tourEnCour = listeTour.get(listeTour.size() - 1);
		if (!tourEnCour.phaseSuivante()) {
			System.out.print("[");
			int annee = tourEnCour.getNextAnnee();
			String saison = tourEnCour.getNextSaison();
			Tour tourSuivant = new Tour(annee, saison);
			listeTour.add(tourSuivant);
		}
		notifierIntJeu();
	}

	@Override
	public void connectIntJeu(IJeuInterface jeuInterface) throws RemoteException {
		listJeuInterface.add(jeuInterface);
	}

	@Override
	public void notifierIntJeu() throws RemoteException {
		System.out.println("taille : " + listJeuInterface.size());
		for (IJeuInterface jeu : listJeuInterface) {
			System.out.println("demande notif");
			jeu.receptionNotification();
		}
	}

	@Override
	public void afficheEtatPartie() throws RemoteException {

		System.out.println("");
		System.out.println("");
		System.out.println("ETAT DE LA PARTIE");
		System.out.println("");

		System.out.println("-------------- liste des joueurs -------------- ");
		for (IJoueur joueur : listeJoueur) {
			System.out.println(joueur.getNom());
			for (Puissance puissance : joueur.getListPuissance()) {
				System.out.println("    " + puissance.getNom());
			}
		}
		System.out.println("-------------- Tour actuel -------------------- ");
		System.out.println(listeTour.get(listeTour.size() - 1).getInfo());
		System.out.println("-------------- Unités ------------------------- ");
		int compteur = 0;
		for (String key : carte.keySet()) {
			if (carte.get(key).getOccupant() != null) {
				System.out.print(carte.get(key).getNom() + "  ");
				compteur++;
				System.out.println(carte.get(key).getOccupant().getTypeUnite() + "("
						+ carte.get(key).getOccupant().getProprietaire().getNom() + ")");

			}
		}

		System.out.println("(" + compteur + ")");
		/*
		 * System.out.println("-------------- carte -------------- "); for
		 * (String key : carte.keySet()) {
		 * System.out.println(carte.get(key).getNom() + " " +
		 * carte.get(key).num); carte.get(key).num = 2;
		 * 
		 * } System.out.println("-------------- carte2 -------------- "); for
		 * (IJoueur joueur : listeJoueur) { for (Puissance puissance :
		 * joueur.getListPuissance()) { for (Region region :
		 * puissance.getListeRegionsPossedes()) {
		 * System.out.println(region.getNom() + " " + region.num); region.num =
		 * 4; System.out.println(region.getNom() + " " + region.num); } } }
		 * System.out.println("-------------- carte3 -------------- "); for
		 * (IJoueur joueur : listeJoueur) { for (Puissance puissance :
		 * joueur.getListPuissance()) { for (Region region :
		 * puissance.getListeregionDepart()) {
		 * System.out.println(region.getNom() + " " + region.num); } } }
		 * System.out
		 * .println("----------------------------------------------- ");
		 * System.out.println(""); System.out.println("");
		 */
	}

	@Override
	public void initGroupePuissance(int nbJoueur) throws RemoteException {
		configuration.initListePuissance(nbJoueur);
	}

	@Override
	public void initElementCarteDepart() {
		for (IJoueur joueur : listeJoueur) {
			try {
				for (Puissance puissance : joueur.getListPuissance()) {
					puissance.initDepart();
				}
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

	}

	@Override
	public boolean regionExist(String nomReg) {
		return carte.containsKey(nomReg.toLowerCase());
	}

	@Override
	public Region getRegion(String nomReg) {
		return carte.get(nomReg.toLowerCase());
	}

	@Override
	public Region getRegionWithPos(Coordonnee coo) {
		Region res = null;
		for (String mapKey : carte.keySet()) {
			Region region = carte.get(mapKey);
			if (region.getCoordoUnite().equals(coo) || region.getCoordoRavitaillement().equals(coo)) {
				res = region;
				break;
			}
		}
		return res;

	}
}
